package OperationSystem.day1203blocking_queue_阻塞队列;

//队列中的元素类型是int类型
public class CircleQueue {//循环队列
    private static final int CAPACITY = 16;

    private int[] queue = new int[CAPACITY];
    private int size = 0;
    private int frontIndex = 0;
    private int rearIndex = 0;

    //放入队列
    public synchronized void put(int element) throws InterruptedException {//生产者调用的
        //判满
        if (size == queue.length) {
            //throw new RuntimeException("队列已满");
            wait();//生产者阻塞，等待消费者唤醒
        }
        //还有空间,放入，下标+1
        queue[rearIndex] = element;
        rearIndex = rearIndex + 1;
        //放完后判断是否满了
        if (rearIndex == queue.length) {
            rearIndex = 0;
        }
        size++;
        System.out.println(size);
        this.notify();//生产者唤醒一个消费者

        /**
         * 思考：单生产者单消费者模式下，notify()方法和size++位置可以互换吗？
         * 是可以的，消费者调用wait()了，被生产者的notify()唤醒后，消费者还是需要去抢锁的！！！
         * 而生产者并没有释放锁！！！
         *所以，生产者唤醒了消费者，消费者也无法执行，需要等生产者释放锁后，消费者去抢锁，抢到了才能执行。
         */


    }

    //从队列中取
    public synchronized int take() throws InterruptedException {//消费者调用的
        //判断为空
        if (size == 0) {
            //throw new RuntimeException("队列为空");
            wait();//消费者阻塞，等待生产者唤醒

        }
        //队列不为空
        int element = queue[frontIndex];
        frontIndex += 1;
        if (frontIndex == queue.length) {
            frontIndex = 0;
        }
        size--;
        //消费者消费掉一个元素，队列一定不满了，就可以尝试唤醒一个生产者了
        this.notify();//试图唤醒等待的生产者

        return element;
    }
}
